#include "binaryoperator.h"

#include <cmath>

namespace AltMath {
     ExpressionTreeNode::Result BinaryOperator::evaluate() const {
          Result r1 = left()->evaluate();
          Result r2 = right()->evaluate();
          Result result;
          if(!r1.success){
               result.success = false;
               result.message = r1.message;
          } else if(!r2.success){
               result.success = false;
               result.message = r2.message;
          } else if(m_operation == Addition){
               result.value = r1.value + r2.value;
          } else if(m_operation == Subtraction){
               result.value = r1.value - r2.value;
          } else if(m_operation == Multiplication){
               result.value = r1.value * r2.value;
          } else if(m_operation == Division){
               if(r2.value == 0.0){
                    result.success = false;
                    result.message = "Division by zero is undefined.";
               } else {
                    result.value = r1.value / r2.value;
               }
          } else if(m_operation == Exponentiation){
               if((r1.value == 0.0)&&(r2.value <= 0.0)){
                    result.success = false;
                    result.message = "Raising 0 to a power less than or greater than 0 is undefined.";
               } else if((r1.value <= 0.0) && (std::floor(r2.value) != r2.value)){
                    result.success = false;
                    result.message = "Non-real result.";
               } else {
                    result.value = std::pow(r1.value, r2.value);
               }
          } else if(m_operation == Modulo){
               if(r2.value == 0.0){
                    result.success = false;
                    result.message = "Modulo by zero is undefined.";
               } else {
                    result.value = std::modf(r1.value, &r2.value);
               }
          }
          return result;
     }

     BinaryOperator::Operation BinaryOperator::operation() const {
          return m_operation;
     }

     int BinaryOperator::precedence(Operation op){
          switch(op){
               case Addition:{
                    return 0;
               }
               case Subtraction:{
                    return 0;
               }
               case Multiplication:{
                    return 1;
               }
               case Division:{
                    return 1;
               }
               case Exponentiation:{
                    return 2;
               }
               case Modulo:{
                    return 2;
               }
          }
          return -1;
     }

     void BinaryOperator::setOperation(Operation op){
          m_operation = op;
          return;
     }
}
